home *** CD-ROM | disk | FTP | other *** search
- /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- /* Graphics3D.c
- /*
- /* 3D graphics and math routines
- /*
- /* Author: Michael Chen, Human Interface Group / ATG
- /* Copyright © 1991-1993 Apple Computer, Inc. All rights reserved.
- /*
- /* Part of Virtual Sphere Sample Code Release v1.1
- /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
-
- #ifndef __GRAPHICS3D__
- #include "Graphics3D.h"
- #endif
-
- #ifndef __FIXMATH__
- #include <FixMath.h>
- #endif
-
- #ifndef __LIMITS__
- #include <Limits.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #include "Sample.h"
-
- /* Structure used for dithering patterns */
- typedef struct {
- short patListSize; /* Size */
- Pattern patList[1]; /* Pointer to varible size arrary */
- } **PatListHandle;
-
- /* Local globals for this file (module) only */
- static ConstPatternParam lgPolyShade;
- static PatListHandle lgDitherPatterns = nil;
-
- /* Local routine */
- static unsigned long RGBToGrayscale (const RGBColor *rGBColor, Integer maxGrayValue);
-
- /*=================================================================================================
- /* InitializeGraphics3D
- /*-------------------------------------------------------------------------------------------------*/
- pascal OSErr InitializeGraphics3D ()
- {
- OSErr err;
-
- /* Load in dither patterns for black and white drawing. */
- if (lgDitherPatterns == nil) {
- lgDitherPatterns = (PatListHandle) GetResource ('PAT#', rDitherPatterns);
- if (lgDitherPatterns == nil) return (resNotFound);
-
- /* Move the dithering pattern as high up in memory as possible and
- * and lock it down. */
- DetachResource ((Handle) lgDitherPatterns); if ((err = MemError()) != noErr) return (err);
- MoveHHi ((Handle) lgDitherPatterns); if ((err = MemError()) != noErr) return (err);
- HNoPurge ((Handle) lgDitherPatterns); if ((err = MemError()) != noErr) return (err);
- HLock ((Handle) lgDitherPatterns); if ((err = MemError()) != noErr) return (err);
- }
- return (noErr);
- }
-
- /*=================================================================================================
- /* FreeGraphics3D
- /*-------------------------------------------------------------------------------------------------*/
- pascal void FreeGraphics3D ()
- {
- /* Dispose the memeory used for the dither patterns */
- if (lgDitherPatterns == nil) {
- DisposeHandle ((Handle) lgDitherPatterns);
- }
- }
-
- /*=================================================================================================
- /* CopyMatrix
- /*-------------------------------------------------------------------------------------------------*/
- typedef struct { /* Struct to make matrix copying more efficient */
- Matrix4D a;
- } MatrixAsStruct;
-
- pascal void CopyMatrix (Matrix4D fromMatrix, Matrix4D toMatrix)
- {
- * (MatrixAsStruct *) toMatrix = * (MatrixAsStruct *) fromMatrix;
- }
-
- /*=================================================================================================
- /* CrossProduct3D
- /*
- /* Returns the right-handed cross-product of a and b in c
- /*-------------------------------------------------------------------------------------------------*/
- pascal void CrossProduct3D (const CPoint3D *a, const CPoint3D *b, CPoint3D *aCrossB)
- {
- aCrossB->x = a->y * b->z - a->z * b->y;
- aCrossB->y = a->z * b->x - a->x * b->z;
- aCrossB->z = a->x * b->y - a->y * b->x;
- }
-
- /*=================================================================================================
- /* DotProduct3D
- /*
- /* Returns the dot-product of a and b
- /*-------------------------------------------------------------------------------------------------*/
- pascal Real DotProduct3D (const CPoint3D *a, const CPoint3D *b)
- {
- return (a->x*b->x + a->y*b->y + a->z*b->z);
- }
-
- /*=================================================================================================
- /* DrawPolyNet
- /*
- /* Draws a PolyNet object with different backfaced polygon removal and rendering options.
- /*-------------------------------------------------------------------------------------------------*/
- pascal void DrawPolyNet (const PolygonNetData *polyNet)
- {
- Point3D *vertices; /* local index into the vertex array */
- Integer *vertexIndices;
- Integer i;
-
- if (polyNet->fVertexCount < 0) DebugMessage ("\pfVertexCount < 0");
-
- vertices = polyNet->fVertices;
- vertexIndices = polyNet->fVertexIndices;
-
- /* For each polygon... */
- for (i = 0; i < polyNet->fPolygonCount; i++) {
- Integer firstVertexIndex;
- NetPolygon *thisPoly = &polyNet->fPolys[i];
- if (thisPoly->fVertexCount < 3) continue; /* This is not a polygon. Skip to next one. */
- firstVertexIndex = thisPoly->fFirstVertexIndex;
-
- if (gDoBackfacedPolygonRemoval) {
- /* Transform first 3 points to screen coordinate to do backface polygon test.
- * Code will not work if any vertex is offscreen!
- */
- Point p0, p1, p2;
- Integer v1h, v1v, v2h, v2v;
-
- MoveTo3D (vertices [vertexIndices [firstVertexIndex ]].x,
- vertices [vertexIndices [firstVertexIndex ]].y,
- vertices [vertexIndices [firstVertexIndex ]].z);
- GetPen (&p0);
- MoveTo3D (vertices [vertexIndices [firstVertexIndex+1]].x,
- vertices [vertexIndices [firstVertexIndex+1]].y,
- vertices [vertexIndices [firstVertexIndex+1]].z);
- GetPen (&p1);
- MoveTo3D (vertices [vertexIndices [firstVertexIndex+2]].x,
- vertices [vertexIndices [firstVertexIndex+2]].y,
- vertices [vertexIndices [firstVertexIndex+2]].z);
- GetPen (&p2);
-
- v1h = p1.h - p0.h;
- v1v = p1.v - p0.v;
- v2h = p2.h - p1.h;
- v2v = p2.v - p1.v;
-
- /* Check for backfaced polygon by doing cross-product. Skip if backfaced.
- * Try using '<=' test instead to get the inside-out effect */
- if ((v1h * v2v - v1v * v2h) >= 0) continue;
- }
-
- {
- /* Draw the polygon */
-
- PolyHandle polyHdl = nil;
- Integer j;
- Integer vertexIndex;
-
- if (gRenderingStyle != iLineDrawing) {
- /* gRenderingStyle is iFlatShading or iFlatShadingWithOutline.
- * Begin collecting QD polygon */
- polyHdl = OpenPoly ();
- }
- PolyColor (&polyNet->fColor [thisPoly->fColorIndex]);
-
- /* Initial move */
- vertexIndex = vertexIndices [firstVertexIndex];
- MoveTo3D ( vertices [vertexIndex].x,
- vertices [vertexIndex].y,
- vertices [vertexIndex].z);
- /* Hit the vertices */
- for (j = firstVertexIndex+1; j < firstVertexIndex+thisPoly->fVertexCount; j++){
- vertexIndex = vertexIndices [j];
- LineTo3D( vertices [vertexIndex].x,
- vertices [vertexIndex].y,
- vertices [vertexIndex].z);
- }
- /* Close the polygon */
- vertexIndex = vertexIndices [firstVertexIndex];
- LineTo3D ( vertices [vertexIndex].x,
- vertices [vertexIndex].y,
- vertices [vertexIndex].z);
-
- if (gRenderingStyle != iLineDrawing) {
- ClosePoly (); /* Stop collecting QD polygon */
- FillPoly (polyHdl, lgPolyShade);
- if (gRenderingStyle == iFlatShadingWithOutline) {
- ForeColor (blackColor);
- FramePoly (polyHdl);
- }
- KillPoly (polyHdl);
- }
- }
- }
- }
-
- /*=================================================================================================
- /* Length3D
- /*
- /* Returns the length of vector a
- /*-------------------------------------------------------------------------------------------------*/
- pascal Real Length3D (const CPoint3D *a)
- {
- return (sqrt (a->x*a->x + a->y*a->y + a->z*a->z));
- }
-
- /*=================================================================================================
- /* Matrix2XfMatrix
- /*
- /* Converts a Matrix4D to a XfMatrix used by Graf3D
- /*-------------------------------------------------------------------------------------------------*/
- pascal void Matrix2XfMatrix (Matrix4D fromMatrix, XfMatrix toMatrix)
- {
- Integer i, j;
-
- for (i=3; i>=0; i--) {
- for (j=3; j>=0; j--) {
- toMatrix[i][j]= Real2Fix (fromMatrix[i][j]);
- }
- }
-
- #ifdef xxxxxxxxxxxxxxxxxxxxxxxxxNOT_USEDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- /* Faster but kludgy version of the same thing */
-
- Real *fromPtr = (Real *) fromMatrix;
- Fixed *toPtr = (Fixed *) toMatrix;
- Integer i;
- for (i=15; i>=0; i--) {
- *toPtr++ = Real2Fix (*fromPtr++);
- }
- #endif xxxxxxxxxxxxxxxxxxxxxxxxxNOT_USEDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- }
-
- /*=================================================================================================
- /* MultiplyMatrix
- /*
- /* Matrix multiplication c = a x b
- /*-------------------------------------------------------------------------------------------------*/
- pascal void MultiplyMatrix (Matrix4D a, Matrix4D b, Matrix4D aTimesB)
- {
- Integer i, j, k;
-
- for (i=3; i>=0; i--) {
- for (j=3; j>=0; j--) {
- Real sum = 0.0;
- for (k=3; k>=0; k--) {
- sum += a[i][k] * b[k][j];
- }
- aTimesB[i][j]= sum;
- }
- }
- }
-
- /*=================================================================================================
- /* Normalize3D
- /*
- /* Returns the normalized vector
- /*-------------------------------------------------------------------------------------------------*/
- pascal void Normalize3D (CPoint3D *v)
- {
- Real length;
-
- length = sqrt (v->x * v->x + v->y * v->y + v->z * v->z);
- if (length > 0) {
- v->x /= length;
- v->y /= length;
- v->z /= length;
- } else {
- /* Vector is zero. Probably should set some error */
- v->x = v->y = v->z = 0;
- DebugMessage ("\p Normalize3D: zero vector!");
- }
- }
-
- /*=================================================================================================
- /* OrthogonalizeRotationMatrix
- /*
- /* Orthogonalizes a pure rotation matrix (this is not checked!).
- /* Assumes the "y-axis" (2nd row) of the matrix is "correct"
- /* and make 1st and 3rd row orthogonal to it.
- /* Assumes matrix is already close to orthogonal.
- /*-------------------------------------------------------------------------------------------------*/
- pascal void OrthogonalizeRotationMatrix (Matrix4D matrix)
- {
- CPoint3D xAxis, yAxis, zAxis;
-
- yAxis.x = matrix[1][0];
- yAxis.y = matrix[1][1];
- yAxis.z = matrix[1][2];
- zAxis.x = matrix[2][0];
- zAxis.y = matrix[2][1];
- zAxis.z = matrix[2][2];
-
- Normalize3D (&yAxis);
- UnitCrossProduct3D (&yAxis, &zAxis, &xAxis);
- UnitCrossProduct3D (&xAxis, &yAxis, &zAxis);
-
- matrix[0][0] = xAxis.x;
- matrix[0][1] = xAxis.y;
- matrix[0][2] = xAxis.z;
-
- matrix[1][0] = yAxis.x;
- matrix[1][1] = yAxis.y;
- matrix[1][2] = yAxis.z;
-
- matrix[2][0] = zAxis.x;
- matrix[2][1] = zAxis.y;
- matrix[2][2] = zAxis.z;
- }
-
- /*=================================================================================================
- /* PolyColor
- /*
- /* Given a RGB color, calls the appropriate QuickDraw routines to set up the
- /* appropriate drawing environment. If gDrawInColor is false (because of a
- /* menu choice or color QD is not available) the color is replaced by a
- /* dithering pattern.
- /*-------------------------------------------------------------------------------------------------*/
- pascal void PolyColor (const RGBColor *rGBColor)
- {
- if (gDrawInColor) {
- lgPolyShade = qd.black;
- RGBForeColor (rGBColor);
- } else {
- /* Convert rGBColor to a dither pattern. */
- unsigned long index;
- index = RGBToGrayscale (rGBColor, (**lgDitherPatterns).patListSize);
- lgPolyShade = (**lgDitherPatterns).patList [index];
- ForeColor (blackColor);
- }
- }
-
- /*=================================================================================================
- /* RGBToGrayscale
- /*
- /* Given a RGB color, convert it to a grayscale value from 0 to (maxGrayValue-1).
- /*-------------------------------------------------------------------------------------------------*/
- static unsigned long RGBToGrayscale (const RGBColor *rGBColor, Integer maxGrayValue)
- {
- #define kRWeight 3
- #define kGWeight 6
- #define kBWeight 1
- #define kTotalWeight (kRWeight + kGWeight + kBWeight)
-
- unsigned long intensity;
- unsigned long index;
- intensity = kRWeight*rGBColor->red + kGWeight*rGBColor->green +
- kBWeight*rGBColor->blue;
- index = intensity * maxGrayValue / kTotalWeight / (USHRT_MAX+1);
- /* Note integer math. Order matters */
- return (index);
- }
-
- /*=================================================================================================
- /* SetRotationMatrix
- /*
- /* Computes a rotation matrix that would map (rotate) vectors op onto oq.
- /* The rotation is about an axis perpendicular to op and oq.
- /* Note this routine won't work if op or oq are zero vectors, or if they
- /* are parallel or antiparallel to each other. Note the implementation below
- /* is easy to read but is not done in the most efficient way. It can be
- /* sped up by reusing some of the temporary results.
- /*
- /* Modification of Michael Pique's formula in
- /* Graphics Gems Vol. 1. Andrew Glassner, Ed. Addison-Wesley.
- /*-------------------------------------------------------------------------------------------------*/
- pascal void SetRotationMatrix (Matrix4D rotationMatrix, const CPoint3D *op, const CPoint3D *oq)
- {
- Real s, c, t;
- CPoint3D a;
-
- #define ax (a.x)
- #define ay (a.y)
- #define az (a.z)
- #define ax2 (ax * ax)
- #define ay2 (ay * ay)
- #define az2 (az * az)
-
- CrossProduct3D (op, oq, &a);
- s = Length3D (&a);
- c = DotProduct3D (op, oq);
- t = 1 - c;
-
- if (s > 0) {
- a.x /= s;
- a.y /= s;
- a.z /= s;
- }
-
- rotationMatrix[0][0] = t*ax2+c;
- rotationMatrix[0][1] = t*ax*ay+s*az;
- rotationMatrix[0][2] = t*ax*az-s*ay;
-
- rotationMatrix[1][0] = t*ax*ay-s*az;
- rotationMatrix[1][1] = t*ay2+c;
- rotationMatrix[1][2] = t*ay*az+s*ax;
-
- rotationMatrix[2][0] = t*ax*az+s*ay;
- rotationMatrix[2][1] = t*ay*az-s*ax;
- rotationMatrix[2][2] = t*az2+c;
-
- rotationMatrix[0][3] = rotationMatrix[1][3] = rotationMatrix[2][3] =
- rotationMatrix[3][0] = rotationMatrix[3][1] = rotationMatrix[3][2] = 0.0;
- rotationMatrix[3][3] = 1.0;
-
- #undef ax
- #undef ay
- #undef az
- #undef ax2
- #undef ay2
- #undef az2
- }
-
- /*=================================================================================================
- /* UnitCrossProduct3D
- /*
- /* Returns the normalized right-handed cross product of a and b in c
- /*-------------------------------------------------------------------------------------------------*/
- pascal void UnitCrossProduct3D (const CPoint3D *a, const CPoint3D *b, CPoint3D *aCrossB)
- {
- CrossProduct3D (a, b, aCrossB);
- Normalize3D (aCrossB);
- }
-
-